home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-28 | 15.5 KB | 739 lines | [TEXT/MPS ] |
- #ifndef __CDENT__
- #include "cdent.h"
- #endif
-
- #ifndef __DFILE__
- #include "DFile.h"
- #endif
-
- #ifndef __FORMATLOG__
- #include "FormatLog.h"
- #endif
-
- #ifndef __CSCANNER__
- #include "CScanner.h"
- #endif
-
- #ifndef __FORMATSTRINGS__
- #include "FormatStrings.h"
- #endif
-
- #ifndef __FORMATTING__
- #include "Formatting.h"
- #endif
-
- #ifndef __PARSER__
- #include "Parser.h"
- #endif
-
- #ifndef __STDFILE__
- #include "StdFile.h"
- #endif
-
- #ifndef __STACK__
- #include "Stack.h"
- #endif
-
- #ifndef __CURSORCTL__
- #include <CursorCtl.h>
- #endif
-
- #ifndef __NEW__
- #include <new.h>
- #endif
-
- #ifndef __SEGLOAD__
- #include <segload.h>
- #endif
-
- #ifndef __STDARG__
- #include <stdarg.h>
- #endif
-
- #ifndef __STDLIB__
- #include <stdlib.h>
- #endif
-
- #ifndef __CTYPE__
- #include <ctype.h>
- #endif
-
-
- #pragma segment ToolMain
-
- extern pascal void _DATAINIT();
-
-
- Severity gDiagLevel = kDiagnostic; // Diagnostics and more
-
-
- //ƒ-
- static const char gVersion[] = "cdent v0.0a0";
- static const char* gInputFilename = "standard input";
- static const char* gOutputFilename = 0;
- static FormatLog gFormatLog; // For saving commands
- static CScanner gScanner; // That which scans
- static Formatting gFormat;
- static Parser gParser; // The one global parser
- static Stack gFormatStack; // Save formatting info around "#if"
- static Stack gParserStack; // Save parse state around "#if"
-
- static Boolean gOption_x = false; // true if "-x" specified
- static Boolean gOption_y = false; // true if "-y" specified
- static Boolean gOption_z = false; // true if "-z" specified
- //ƒ+
-
-
- static void doOption(int argc, char *argv[], int &i);
- static Boolean isArg(int argc, int i, const char *option);
- static void badOption(const char *arg);
- static int getNumber(int argc, char *argv[], int i);
- static Boolean isFormatOption(int argc, char *argv[], int i);
- static char *lower(register char *aString);
- static Boolean ustreql(const char *a, const char *b);
-
-
- // main
- #pragma segment ToolMain
- void main(int argc, char *argv[])
- {
- StdFile * nullFile = new StdFile("Dev:Null", "w");
- StdFile * inputFile;
- StdFile * outputFile = &gStdout;
- short anErr;
- int i;
- DFile outputDFile;
-
-
- // Unload the initialization segment
- UnloadSeg(_DATAINIT);
-
- // Initialize the cursor
- InitCursorCtl(0);
-
- // Initialize the global data objects
- gFormatLog.IFormatLog();
- gScanner.ICScanner();
- gFormat.IFormatting();
- gParser.IParser();
- gFormatStack.IStack(16, 4);
- gParserStack.IStack(16, 4);
-
- /*
- ** Open the input file
- */
- setvbuf(stderr, 0, _IOFBF, BUFSIZ); // To make dumps faster
- inputFile = &gStdin;
- gParser.DebugParser(false);
-
- // Construct the DFile used for output
- outputDFile.IDFile(64, 64);
- outputDFile.SetOutput(outputFile);
- gFormat.SetOutput(&outputDFile);
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- doOption(argc, argv, i);
- } else {
- gInputFilename = argv[i];
- inputFile = new StdFile(argv[i], "r");
- if (inputFile == 0 || (FILE *)inputFile == NULL)
- diag(kFatal, "Could not open %s\n", argv[i]);
- }
- }
-
-
- /*
- ** Check if any special case options were checked
- */
- if (gOption_x) {
- }
-
- if (gOption_y) {
- }
-
- if (gOption_z) {
- }
-
- // Re-apply any specific glue
- for (i = 1; i < argc; i++)
- if (argv[i][0] == '-')
- isFormatOption(argc, argv, i);
-
-
- /*
- ** Allocate the buffer for it and read it in
- */
- size_t inputSize = inputFile->GetSize();
-
- if (inputSize == 0)
- inputSize = 1024;
-
- DataArea inputArea;
- anErr = inputArea.IDataArea();
- if (anErr != noErr)
- diag(kFatal, "Could not allocate memory for file (%d)\n", anErr);
-
- size_t amtRead = 1;
- while (amtRead != 0) {
- // Allocate space for the data
- if (inputArea.Require(inputSize) < inputSize)
- diag(kFatal, "Could not allocate memory while reading\n");
-
- // Read the data into the area allocate, advance the cursor
- inputArea.HLock();
- amtRead = inputFile->Read(*inputArea.GetHandle(), inputSize);
- inputArea.HUnlock();
- inputArea.IncrCursor(amtRead);
-
- // When nothing else remains to be read, write a terminating null
- // and lock the buffer out of the way.
- if (amtRead == 0) {
- char aZero = 0;
-
- inputArea.Write(&aZero, sizeof(aZero));
- inputArea.Truncate();
- inputArea.MoveHHi();
- inputArea.HLock();
- }
- }
- inputFile->Close();
-
- // Point to the input buffer
- char *inputBuffer = (char *) * inputArea.GetHandle();
-
-
- /*
- ** Open the output file if gOutputFilename has been set.
- */
- if (gOutputFilename != 0) {
- outputFile = new StdFile(gOutputFilename, "w");
- if (outputFile == 0)
- diag(kFatal, "Could not open output file %s\n", gOutputFilename);
- }
-
-
- /*
- ** Scan and display the results.
- ** "done" is true when an eof has been read. "currentOutputFile" is
- ** normally &gStdout. It is controlled by comments (kSLex_Comment)
- ** whose minor types are either kSLex_CommentFormatOn or
- ** kSLex_CommentFormatOff. When formatting is on, display is done by
- ** the parser. When formatting is off, the variable "lastBufferEnd" is
- ** the text position of the next character after the just scanned token.
- ** We display the text (via gStdout.Write()) starting at lastBufferEnd
- ** upto the end of the token. lastBufferEnd is then updated.
- */
-
- // Construct the DFile used for output
- StdFile * currentOutputFile = outputFile;
- outputDFile.SetOutput(currentOutputFile);
-
- // Fix up the input buffer
- inputBuffer[inputSize] = '\0';
- gScanner.ScanThis(inputBuffer, inputSize);
- gParser.SetFormatting(&gFormat);
- gFormat.SetFormatLog(&gFormatLog);
-
- Boolean done = false;
- size_t lastBufferEnd = 0; // Shut up the compiler
-
- while (!done) {
- Syntactic * aToken = gScanner.NextToken();
-
- switch (aToken->Type()) {
- case kSErr:
- diag(kFatal, "Bad token near: %40s\n", gScanner.Text());
- break;
-
- case kSLex_EOF:
- gParser.Parse();
- gFormat.Display(aToken);
- done = true;
- break;
-
- case kSLex_PoundLine:
- // Flush any partial states in the parser, assuring that tokens
- // are emitted. Then make sure that the PoundLine is on a fresh
- // line by itself.
- gParser.Parse();
- gFormat.ExecuteGlue((FormatString)"&n");
-
- // Handle a preprocessor line. The MinorType() of the token describes
- // which type of preprocessor line it is.
- switch (aToken->MinorType()) {
- case kSLex_PoundIf:
- // Save the current formatting and parsing info
- {
- Formatting * newFormatting = new Formatting;
- Parser * newParser = new Parser;
-
- newFormatting->IFormatting(&gFormat);
- newParser->IParser(&gParser);
-
- gFormatStack.Push(newFormatting);
- gParserStack.Push(newParser);
- }
- break;
-
- case kSLex_PoundElif:
- case kSLex_PoundElse:
- case kSLex_PoundEndIf:
- // Restore the last saved formatting & parsing info when a
- // #else or #elif is scanned. If a #endif is scanned, we
- // keep using the parsing information from the preceding
- // conditional then or conditional else part. This will
- // minimize the number of parse errors which occur when users
- // do obscene things like put closing parens/curlys in both
- // arms of the conditional compile expression.
- // If this is a #endif, then pop the stacks of saved information
- // and destruct them
- if (gFormatStack.IsEmpty())
- diag(kFatal, "Unbalanced conditional compilation: not enough #if\n");
-
- if (aToken->MinorType() == kSLex_PoundEndIf) {
- delete(Formatting * )gFormatStack.Pop();
- delete(Parser * )gParserStack.Pop();
- } else {
- // Make damn sure the copy constructor is called...
- // Make gFormat write to the current outputFile
- gFormat.IFormatting((Formatting *)gFormatStack.Top());
- gParser.IParser((Parser *)gParserStack.Top());
- outputDFile.SetOutput(currentOutputFile);
- }
- break;
- }
-
- if (currentOutputFile != nullFile)
- gParser.Parse(aToken);
- else {
- // Display from the last token to this token
- size_t endOfToken = gScanner.CharPos() + gScanner.TokenLength();
- outputFile->Write(&inputBuffer[lastBufferEnd], endOfToken - lastBufferEnd);
- lastBufferEnd = endOfToken;
- }
- break;
-
- default:
- // Always let the parser see the token, even if its output is
- // the null file.
- if (!gParser.Parse(aToken)) {
- gFormat.Flush();
- if (gParser.DebugParser())
- gParser.DumpStack(gStderr);
- diag(kFatal, "Syntax Error");
- }
-
- // Write the token if the output is the null file.
- if (currentOutputFile == nullFile) {
- // Display from the last token to this token
- size_t endOfToken = gScanner.CharPos() + gScanner.TokenLength();
- outputFile->Write(&inputBuffer[lastBufferEnd], endOfToken - lastBufferEnd);
- lastBufferEnd = endOfToken;
- }
-
- // Check if this is a comment controlling formatting
- if (aToken->Type() == kSLex_Comment) {
- switch (aToken->MinorType()) {
- case kSLex_CommentFormatOff:
- gParser.Parse();
- currentOutputFile = nullFile;
- outputDFile.SetOutput(currentOutputFile);
- lastBufferEnd = gScanner.CharPos() + gScanner.TokenLength();
- break;
-
- case kSLex_CommentFormatOn:
- currentOutputFile = outputFile;
- outputDFile.SetOutput(currentOutputFile);
- break;
- }
- } else if (aToken->Type() == kSLex_NewLine)
- SpinCursor(7);
- break;
- }
- }
-
- // Write any unwritten output
- gFormat.Flush();
- exit(EXIT_SUCCESS);
- }
-
-
-
- // diag
- #pragma segment ToolMain
- void diag(Severity aLevel, const char *aFmt, ...)
- {
- va_list ap;
-
- va_start(ap, aFmt);
- if (aLevel >= gDiagLevel) {
- gFormat.Flush(); // Force any output
- if (aLevel >= kDiagnostic)
- fputs("# ", stderr);
- vfprintf(stderr, aFmt, ap);
- }
-
- if (aLevel >= kFatal) {
- fprintf(stderr, "\nFile %s; Line %d\n", gInputFilename, gScanner.LineNumber());
- exit(9);
- }
-
- va_end(ap);
- }
-
-
-
-
- /*
- ** doOption
- ** Process option argv[i]. The index "i" is passed by reference to allow
- ** it to be advanced if other arguments must be consumed.
- */
- #pragma segment ToolMain
- static void doOption(int argc, char *argv[], int &i)
- {
- const char *option = argv[i] + 1; // Advance past the '-'
-
- if (option[1] == '\0') {
- // Single character flag
- switch (tolower(option[0])) {
- case 'o': // -o Output file
- if (!isArg(argc, i + 1, option))
- return;
- gOutputFilename = argv[++i];
- break;
-
- case 'p': // -p Report progress
- gDiagLevel = kProgress;
- diag(kProgress, "%s\n", gVersion);
- break;
-
- case 't': // -t Set the tab width
- gFormat.TabSize(getNumber(argc, argv, i));
- i++;
- break;
-
- case 'x': // -x No spaces around operators
- gOption_x = true;
- break;
-
- case 'y': // -y No spaces around assignment
- gOption_y = true;
- break;
-
- case 'z': // -y No space after ","
- gOption_z = true;
- break;
-
- default:
- badOption(option);
- break;
- }
- } else {
- // Multi character option
- enum EOption {
- kOptNone //
- , kOpt_indent //
- , kOpt_linelength //
- , kOpt_commentcol //
- , kOpt_allnl //
- , kOpt_nonl //
- , kOpt_trace //
- };
-
-
- struct Option {
- const char *fOptionName; // Name of the option
- EOption fOptionIndex; // Integer of option
- char fOptionNArgs; // # of args required.
- };
-
-
- static Option options[] = {
- //ƒ-
- {"indent", kOpt_indent, 1}
- , {"ll", kOpt_linelength, 1}
- , {"cc", kOpt_commentcol, 1}
- , {"allnl", kOpt_allnl, 0}
- , {"nonl", kOpt_nonl, 0}
- , {"trace", kOpt_trace, 1}
- , {0, kOptNone, 0} // Terminator
- //ƒ+
- };
-
- const Option *p = options;
-
- // Find the option.
- while (p->fOptionName && !ustreql(option, p->fOptionName))
- p++;
-
- // Check that there are enough arguments
- if (!isArg(argc, i + p->fOptionNArgs, option))
- return;
-
- // Process the option
- switch (p->fOptionIndex) {
- case kOpt_indent:
- gFormat.SetIndent(getNumber(argc, argv, i));
- break;
-
- case kOpt_linelength:
- gFormat.LineLength(getNumber(argc, argv, i));
- break;
-
- case kOpt_commentcol:
- gFormat.CommentColumn(getNumber(argc, argv, i));
- break;
-
- case kOpt_allnl:
- gFormat.PassSourceNewLines(true);
- gFormat.PassConsecutiveNewLines(false);
- break;
-
- case kOpt_nonl:
- gFormat.PassSourceNewLines(false);
- gFormat.PassConsecutiveNewLines(false);
- break;
-
- case kOpt_trace:
- gDiagLevel = kDebug;
- if (ustreql(argv[i + 1], "parse")) {
- gParser.DebugParser(true);
- } else if (ustreql(argv[i + 1], "formatting")) {
- gFormat.DebugFormatting(true);
- gParser.DebugFormatting(true);
- } else
- diag(kFatal, "Bad option to -trace: %s\n", argv[i + 1]);
- break;
-
- default:
- if (isFormatOption(argc, argv, i))
- i++;
- else
- badOption(option);
- break;
- }
-
- // Option processing done. Bump "i" by the number of arguments
- // consumed by the option.
- i += p->fOptionNArgs;
- }
- }
-
-
-
- /*
- ** isFormatOption
- ** Return true if the option passed in refers to one of the formats
- */
- #define CASE(x) {#x, &gFS_##x},
-
- #pragma segment ToolMain
- static Boolean isFormatOption(int argc, char *argv[], int i)
- {
- if (i + 1 >= argc)
- return (false);
-
- const char *aName = argv[i] + 1;
- const char *aFormat = lower(argv[i + 1]);
-
- static struct Option2 {
- const char *fName;
- FormatString *fString;
- } options[] = {
- //ƒ-
- CASE(if0)
- CASE(if1)
- CASE(if2)
- CASE(if3)
- CASE(if4)
- CASE(if5)
- CASE(if6)
- CASE(if7)
-
- CASE(else1)
- CASE(else3)
- CASE(else4)
- CASE(else6)
-
- CASE(switch0)
- CASE(switch1)
- CASE(switch2)
- CASE(switch3)
- CASE(switch4)
- CASE(switch5)
- CASE(switch7)
-
- CASE(for0)
- CASE(for1)
- CASE(for3)
- CASE(for4)
- CASE(for5)
- CASE(for6)
- CASE(for7)
- CASE(for8)
-
- CASE(while0)
- CASE(while1)
- CASE(while2)
- CASE(while3)
- CASE(while4)
- CASE(while5)
- CASE(while6)
-
- CASE(do0)
- CASE(do1)
- CASE(do2)
- CASE(do3)
- CASE(do4)
- CASE(do5)
- CASE(do6)
-
- CASE(struct0)
- CASE(struct1)
- CASE(struct2)
- CASE(struct3)
- CASE(struct5)
- CASE(struct6)
- CASE(struct7)
-
- CASE(fundef2)
- CASE(fundef3)
- CASE(fundef4)
- CASE(fundef6)
- CASE(fundef7)
- CASE(fundef8)
- CASE(fundef10)
- CASE(fundef11)
- CASE(fundef12)
- CASE(fundef13)
- CASE(fundef14)
-
- CASE(decl0)
- CASE(decl1)
- CASE(decl2)
- CASE(decl3)
- CASE(decl5)
- CASE(decl6)
- CASE(decl7)
- CASE(decl8)
- CASE(decl9)
- CASE(decl10)
- CASE(decl11)
-
- CASE(stmt0)
- CASE(stmt1)
-
- CASE(expr1)
- CASE(expr2)
- CASE(expr3)
- CASE(expr4)
- CASE(expr5)
- CASE(expr6)
- CASE(expr7)
- CASE(expr8)
-
- CASE(funcall2)
- CASE(funcall3)
- CASE(funcall4)
-
- CASE(label1)
-
- CASE(block1)
- CASE(block2)
-
- CASE(name1)
-
- CASE(goto1)
- CASE(return1)
- CASE(break1)
- {0, 0}
- //ƒ+
- };
-
- for (struct Option2 *anOption = options; anOption->fName; anOption++)
- if (ustreql(anOption->fName, aName)) {
- *anOption->fString = (FormatString)aFormat;
- return (true);
- }
-
- return (false);
- }
-
-
-
- // isArg
- #pragma segment ToolMain
- static Boolean isArg(int argc, int i, const char *option)
- {
- if (i < argc)
- return (true);
-
- diag(kFatal, "Missing %d argument%s to option \"-%s\"\n", i - argc + 1, (i == argc) ? "" : "s", option);
- return (false);
- }
-
-
- // getNumber
- #pragma segment ToolMain
- static int getNumber(int argc, char *argv[], int i)
- {
- if (isArg(argc, i + 1, argv[i])) {
- int n;
-
- if (sscanf(argv[i + 1], "%d", &n) == 1)
- return (n);
- diag(kFatal, "Non-numeric argument to option -%s: %s\n", argv[i], argv[i + 1]);
- }
-
- return (-1);
- }
-
-
-
- // badOption
- #pragma segment ToolMain
- static void badOption(const char *arg)
- {
- diag(kFatal, "Unrecognized option \"-%s\"\n", arg);
- }
-
-
-
- // lower
- #pragma segment ToolMain
- static char *lower(register char *aString)
- {
- char *p = aString;
-
- while (*p) {
- *p = tolower(*p);
- p++;
- }
-
- return (aString);
- }
-
-
-
-
- /*
- ** ustreql
- ** Perform an unsigned comparison of the two strings. Return true
- ** if they are equal, false if they are unequal
- */
- #pragma segment ToolMain
- static Boolean ustreql(const char *a, const char *b)
- {
- if (a != b)
- while (*a && *b && tolower(*a) == tolower(*b)) {
- ++a;
- ++b;
- }
-
- return (*a == *b);
- }
-
-
-